/**
 * package Engine
 */
package ca.csf.dfc.poo.eng;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import ca.csf.dfc.poo.bots.Robot;
import ca.csf.dfc.poo.bots.RobotIntelligent;
import ca.csf.dfc.poo.env.Case;
import ca.csf.dfc.poo.env.Direction;
import ca.csf.dfc.poo.env.Environnement;

/**
 * Classe représentant un objet Engine qui sert à contrôler une liste de robots.
 * 
 * @author Camille Besse
 */
public class Engine
{
    /**
     * L'environnement
     */
    private Environnement environnement;
    /**
     * La liste de robots.
     */
    private ArrayList<Robot> listRobots;

    /**
     * Générateur de nombre aléatoires
     */
    protected Random m_r;

    /**
     * Constructeur d'initialisation. Initialise un objet Engine en fournissant le nom du fichier XML contenant les
     * données de l'environnement.
     * 
     * @param p_Fichier
     *            fichier XML de l'environnement
     * @throws Exception
     */
    public Engine(String p_Fichier, Random p_r) throws Exception
    {
        this.environnement = new Environnement(p_Fichier);
        this.listRobots = new ArrayList<Robot>();
        this.m_r = p_r;
    }

    /**
     * Retourne la liste des robots.
     * 
     * @return the listRobots.
     */
    public ArrayList<Robot> getListRobots()
    {
        return this.listRobots;
    }

    /**
     * Retourne l'environnement.
     * 
     * @return the environnement.
     */
    public Environnement getEnvironnement()
    {
        return this.environnement;
    }

    /**
     * Pour modifier l'environnement
     * 
     * @param p_environnement
     *            Nouvelle valeur.
     */
    protected void setEnvironnement(Environnement p_environnement)
    {
        this.environnement = p_environnement;
    }

    /**
     * Fonction permettant à tous les robots de se déplacer d'une case dans l'environnement et de recevoir leur
     * récompense s'ils passent sur une case payante.
     */
    public void oneStep()
    {
        HashMap<Robot, Direction> aExecuter = new HashMap<Robot, Direction>();
        for (Robot r : listRobots)
            if (this.environnement.getCase(r.getPosition()) == Case.PRISE)
            {
                // re-positionnement aléatoire lorsque le robot
                // arrive sur une prise de courant
                r.setPosition(this.environnement.getNewPos(this.m_r));
            }
            else
            {
                // Récupérer le choix du robot
                HashMap<Direction, Case> p_possibles = this.environnement.getPossibilities(r.getPosition());
                aExecuter.put(r, r.decide(p_possibles));
            }

        //Exécuter "simulatnément" les choix des robots et leur donner leur récompense.
        for (Robot r : aExecuter.keySet())
        {
            Direction d = aExecuter.get(r);
            if(d != null)
            {
            	r.doIt(d);
            	this.giveReward(r);
            }
        }

    }

    /**
     * Fonction qui donne une récompense au robot selon le type de Case sur lequel il se trouve
     * 
     * @param p_Robot
     *            : Un robot
     */
    private void giveReward(Robot p_Robot)
    {
        p_Robot.addAccReward(this.environnement.getCase(p_Robot.getPosition()).getRecompense());
    }

    /**
     * Fonction qui ajoute un nouveau robot dans la liste.
     * 
     * @param p_Robot
     *            : Un robot
     */
    public void addRobot(Robot p_Robot)
    {
        this.listRobots.add(p_Robot);
    }

    /**
     * Redéfinition.
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString()
    {
        return "Engine [environnement=\n" + this.environnement + "\n\n listRobots=\n" + this.listRobots + "]";
    }

    /**
     * Permet d'obtenir la liste des robots intelligents de l'engine.
     * @return Liste des robots intelligents
     */
	public ArrayList<RobotIntelligent> getListRobotsIntelligents()
	{
		ArrayList<RobotIntelligent> lst = new ArrayList<RobotIntelligent>();
		
		for(int i =0;i<this.listRobots.size();i++)
		{
			if (listRobots.get(i) instanceof RobotIntelligent)
			{
				lst.add((RobotIntelligent) listRobots.get(i));
			}
		}
		return lst;
	}
    
    
}
